#include<iostream>
#include<functional>
#include<vector>
#include<memory>
#include<unordered_map>
#include<unistd.h>


using TimeTask = std::function<void()>;
using WeakPtrDeleteTask = std::function<void()>;


//用类来封装定时任务
//1.是为了对象销毁时自动调用析构，一个超时时间点会有多条定时任务，一个clear将对象全部清除，定时任务不就一下完成了
//2.为后面刷新、取消任务做设计
class TimerTask
{
private:
    //每个定时任务得id
    uint64_t clock_id_;
    //每个定时任务得时间
    uint32_t time_out_;
    //超时时，定时任务是否需要完成
    bool cancle_;
    //定时任务得回调，超时了应该做啥
    TimeTask time_task_cb_;
    //weak_ptr销毁得回调，定时任务不在了那么哈希表中也不需要存储weak_ptr了。
    WeakPtrDeleteTask weak_ptr_delete_cb_;


public:
    TimerTask(uint64_t id,uint32_t delay,TimeTask cb):clock_id_(id),time_out_(delay),cancle_(false),time_task_cb_(cb)
    {}
    ~TimerTask()
    {
        if(cancle_ == false)
        {
            time_task_cb_();
        }
        weak_ptr_delete_cb_();
    }

    //weak_ptr的销毁时时间轮来设置得，不用用户传入。
    void setWeakDeleteCallback(WeakPtrDeleteTask cb) {weak_ptr_delete_cb_ = cb;}

    int deleyTime()
    {
        return time_out_;
    }

    void cancleTask()
    {
        cancle_ = true;
    }

};




#define MAX_TIME_OUT 60

class TimerWheel
{
    //定义一个shared_ptr管理TimerTask对象的类型，后面用来
    using SharedptrTimerTask = std::shared_ptr<TimerTask>;
    //定义一个weak_ptr管理TimerTask对象的类型，
    using WeakptrTimerTask = std::weak_ptr<TimerTask>;

private:
    //时间轮超时最大设定值
    int capacity_;
    //秒针
    int tick_;
    //存储定时任务对象得容器（二维）存储的是shaer_ptr包装的对象
    std::vector<std::vector<SharedptrTimerTask>> timer_wheel_;

    //这里用weak_ptr是为了获取我们的任务对象，刷新任务时需要用到
    //不用shared_ptr的原因：如果对同一对象管理，我们shared_ptr对象销毁时需要引用计数为0才能调用管理对象的析构，但是我们的哈希表里的share_ptr对象需要管理对象的析构才能销毁自己。
    //每个定时任务对象和任务id的映射。weak_ptr包装的
    std::unordered_map<uint64_t,WeakptrTimerTask> times_;

public:
    //定义一个最大60秒的时间轮
    TimerWheel():capacity_(MAX_TIME_OUT),tick_(0),timer_wheel_(capacity_)//使用capacity注意声明顺序
    {}

    ~TimerWheel()
    {}

    void timeTaskAdd(uint64_t id,uint32_t delay,TimeTask cb)
    {
        //判断设置的时间是否正确
        if(delay <= 0 || delay > 60) return;

        TimerTask* task = new TimerTask(id,delay,cb);

        SharedptrTimerTask spt(task);
        WeakptrTimerTask wpt(spt);

        timer_wheel_[(tick_ + delay - 1) % capacity_].push_back(spt);

        //传入weak_ptr销毁的回调函数对象
        spt->setWeakDeleteCallback(std::bind(&TimerWheel::removeWeak_ptr,this,id));

        times_[id] = wpt;
    }

    void refreshTimeTask(uint64_t id)
    {
        auto it = times_.find(id);
        if(it == times_.end())
        {
            return;
        }


        SharedptrTimerTask pt = it->second.lock();
        if(pt == nullptr)
        {
            return;
        }

        int delay = pt->deleyTime();

        //将其重新添加进时间轮里面
        timer_wheel_[(tick_ + delay - 1) % capacity_].push_back(pt);

    }

    void cancleTask(uint64_t id)
    {
        auto it = times_.find(id);
        if(it == times_.end())
        {
            return;
        }

        SharedptrTimerTask pt = it->second.lock();
        if(pt == nullptr)
        {
            return;
        }
        //调用取消任务函数
        pt->cancleTask();
    }

    void removeWeak_ptr(uint64_t id)
    {
        auto it = times_.find(id);
        if(it == times_.end())
        {
            return;
        }
        times_.erase(id);
    }

    //1s执行一次
    void run_task()
    {
        //秒针+1
        tick_ = (tick_ + 1) % capacity_;

        //清楚该超时时间点的所有定时任务对象
        timer_wheel_[tick_].clear();
    }

};


class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};



int main()
{
    Test* t = new Test;
    TimerWheel timewheel;
    timewheel.timeTaskAdd(888,5,[t](){delete t;});


    for(int i = 0;i < 5;i++)
    {
        sleep(1);
        timewheel.run_task();
        std::cout << "你的任务已经刷新" << std::endl;
        timewheel.refreshTimeTask(888);
    }


    while(true)
    {
        std::cout << "----------------------------"<< std::endl;
        sleep(1);
        timewheel.run_task();
    }


    return 0;
}